---
title: The RSS reader tutorial (Step 2)
category: guides
authors:
  - name: Pavel Drankov
    github_id: Sammers21
summary: >-
  In this second installment of our Vert.x Cassandra Client tutorial, we will
  add an endpoint that produces an array of RSS channels for a given user ID.
---

In [the previous step](/blog/the-rss-reader-tutorial/), we have successfully implemented the first endpoint 
of the RSS reader app.

The RSS reader example assumes implementing 3 endpoints. This article is dedicated to implementing the `GET /user/{user_id}/rss_channels` endpoint.

Before completing this step, make sure your are in the `step_2` git branch:

```better-shell
$ git checkout step_2
```

## Implementing the second endpoint

The second endpoint produces an array of RSS channels by given `user_id`.

We need to execute the two following queries to:

1. Fetch RSS links for a given user:
    ```sql
    SELECT rss_link FROM rss_by_user WHERE login = GIVEN_USER_ID ;
    ```
2. Fetch RSS channel details for a given link:
    ```sql
    SELECT description, title, site_link, rss_link FROM channel_info_by_rss_link WHERE rss_link = GIVEN_LINK ;
    ```

## Implementation

The endpoint allows the the front-end app to display the list of RSS feeds a user subscribed on. When the endpoint is accessed, the `AppVerticle#getRssChannels` method is called. We can implement this method in this way:

```java
private void getRssChannels(RoutingContext ctx) {
    String userId = ctx.request().getParam("user_id");
    if (userId == null) {
        responseWithInvalidRequest(ctx);
    } else {
        Future<List<Row>> future = Future.future();
        client.executeWithFullFetch(selectRssLinksByLogin.bind(userId), future);
        future.compose(rows -> {
            List<String> links = rows.stream()
                    .map(row -> row.getString(0))
                    .collect(Collectors.toList());

            return CompositeFuture.all(
                    links.stream().map(selectChannelInfo::bind).map(statement -> {
                        Future<List<Row>> channelInfoRow = Future.future();
                        client.executeWithFullFetch(statement, channelInfoRow);
                        return channelInfoRow;
                    }).collect(Collectors.toList())
            );
        }).setHandler(h -> {
            if (h.succeeded()) {
                CompositeFuture result = h.result();
                List<List<Row>> results = result.list();
                List<Row> list = results.stream()
                        .flatMap(List::stream)
                        .collect(Collectors.toList());
                JsonObject responseJson = new JsonObject();
                JsonArray channels = new JsonArray();

                list.forEach(eachRow -> channels.add(
                        new JsonObject()
                                .put("description", eachRow.getString(0))
                                .put("title", eachRow.getString(1))
                                .put("link", eachRow.getString(2))
                                .put("rss_link", eachRow.getString(3))
                ));

                responseJson.put("channels", channels);
                ctx.response().end(responseJson.toString());
            } else {
                log.error("failed to get rss channels", h.cause());
                ctx.response().setStatusCode(500).end("Unable to retrieve the info from C*");
            }
        });
    }
}
```

Also, this method uses `selectChannelInfo` and `selectRssLinksByLogin` fields, they should be initialized in the `AppVerticle#prepareNecessaryQueries` method:


```java
private Future<Void> prepareNecessaryQueries() {
    Future<PreparedStatement> selectChannelInfoPrepFuture = Future.future();
    client.prepare("SELECT description, title, site_link, rss_link FROM channel_info_by_rss_link WHERE rss_link = ? ;", selectChannelInfoPrepFuture);

    Future<PreparedStatement> selectRssLinkByLoginPrepFuture = Future.future();
    client.prepare("SELECT rss_link FROM rss_by_user WHERE login = ? ;", selectRssLinkByLoginPrepFuture);

    Future<PreparedStatement> insertNewLinkForUserPrepFuture = Future.future();
    client.prepare("INSERT INTO rss_by_user (login , rss_link ) VALUES ( ?, ?);", insertNewLinkForUserPrepFuture);

    return CompositeFuture.all(
            selectChannelInfoPrepFuture.compose(preparedStatement -> {
                selectChannelInfo = preparedStatement;
                return Future.succeededFuture();
            }),
            selectRssLinkByLoginPrepFuture.compose(preparedStatement -> {
                selectRssLinksByLogin = preparedStatement;
                return Future.succeededFuture();
            }),
            insertNewLinkForUserPrepFuture.compose(preparedStatement -> {
                insertNewLinkForUser = preparedStatement;
                return Future.succeededFuture();
            })
    ).mapEmpty();
}
```

## Conclusion

In this part, we have successfully implemented the second endpoint, which allows the browser app to obtain channels information for a specific user. To ensure that it is working fine, point your browser to `localhost:8080` and click to the refresh button. Channel list should appear immediately.

If you have any problems with completing this step you can checkout to `step_3`, where you can find all changes made for completing this step:

```better-shell
$ git checkout step_3
```

Thanks for reading this. I hope you enjoyed reading this article. See you soon on our [Gitter channel](https://gitter.im/eclipse-vertx/vertx-users)!
